﻿#import os
#import sys




# Настройка вывода ошибок в файл

# Определяется текущая директория

#__dir__ = os.path.dirname(os.path.abspath(__file__))
#path_error = os.path.join(__dir__, "so_test_error.log")

# Вывод ошибок перенаправляется в файл error.log в текущей директории

#sys.stderr = open(path_error, 'a')


#import postgresql.driver as pg_driver
#import cymysql
#import fdb
#import pypyodbc
#import cx_Oracle

class base:
	"This class connects and disconnects base"
	#print (self.__doc__)
	#beginning of class suite
	def __init__(self):
		self.driver=None
		self.user=None
		self.passwd=None
		self.host=None
		self.port=None
		self.charset=None
		self.base=None
		self.sid=None
		self.dsn=None
		self.cstring=None
		self.state=False
		self.log=None
		self.conn=None
		self.cursor=None

	def open(self):
		"This function opens connection to base"
		#print (self.open.__doc__)
		return
		
	def connect(self):
		"This function is a wrapper for open function"
		#print (self.connect.__doc__)
		#beginning of function suite
		if self.state==False:
			self.open()
			self.state=True
			self.log='Connected'
		else:
			self.log='Already connected'
		#end of function suite
		return 
	
	def close(self):
		"This function closes connection to base"
		#print (self.close.__doc__)
		self.conn.close()
		return
	
	def disconnect(self):
		"This function is a wrapper for close function"
		#print (self.disconnect.__doc__)
		#end of function suite
		if self.state==True:
			self.close()
			self.conn=None
			self.cursor=None
			self.state=False
			self.log='Disconnected'
		else:
			self.log='Already disconnected'
		#end of function suite
		return

	#end of class base suite

class relations:
	"This class counts and select records for base relations"
	#beginning of class suite
	#print (relations.__doc__)
	#Инициализация:
	def __init__(self):
		self.log=None
		self.base=base()
		self.variable=None

	def type(self,type):
		'Function returns base specific type sign'
		return

	def catalogue(self, type):
		'Function returns sql string for the catalogue'
		return
		
	def field(self, type):
		'Function returns sql string for the field'
		return
		
	def list(self, names):
		'Function returns sql string for the list of names'
		return "('"+"','".join(names)+"')"

	def CountString(self, type, names):
		'Function returns sql string for count'
		#Если аргумент names не равен ['']
		if names!=['']:
			string='SELECT COUNT(*) FROM '+self.catalogue(type)+self.field(type)+' IN '+self.list(names)
		else:
			string='SELECT COUNT(*) FROM '+self.catalogue(type)
		return string
	
	def CountlikeString(self, type):
		'Function returns sql string for countlike'
		return 'SELECT COUNT(*) FROM '+self.catalogue(type)+self.field(type)+' LIKE '+self.variable
	
	def SelectString(self, type, names):
		'Function returns sql string for select'
		#Если аргумент names не равен ['']
		if names!=['']:
			string='SELECT * FROM '+self.catalogue(type)+self.field(type)+' IN '+self.list(names)
		else:
			string='SELECT * FROM '+self.catalogue(type)
		return string

	def SelectlikeString(self, type):
		'Function returns sql string for selectlike'
		return 'SELECT * FROM '+self.catalogue(type)+self.field(type)+' LIKE '+self.variable

	def executer(self, string, variable=None):
		return

	#Определяется базовая функция подсчета количества таблиц и видов
	def count(self,type,names):
		'''Function counts relations'''
		#beginning of function suite
		#print(self.count.__doc__)
		#Выполняется подключение к базе данных
		self.base.connect()
		#Переменной result присваивается результат подсчета
		result=self.executer(self.CountString(type, names))[0][0]
		#Закрывается подключение к базе данных
		self.base.disconnect()
		#В переменную класса log записывается лог
		self.log='counted'
		#end of function suite
		#Функция возвращает число таблиц и видов с заданными именами
		return result

	#Определяется базовая функция подсчета количества похожих таблиц и видов
	def countlike(self,type,names):
		'''Function counts like relations'''
		#beginning of function suite
		#print(self.countlike.__doc__)
		#Переменной result присваивается ноль
		result=0
		#Выполняется подключение к базе данных
		self.base.connect()
		for name in names:
			#К значению переменной name добавляются %
			name='%'+name+'%'
			#К переменной result прибавляется результат подсчета строк с заданным именем
			result=result+self.executer(self.CountlikeString(type), name)[0][0]
		#Закрывается подключение к базе данных
		self.base.disconnect()
		#В переменную класса log записывается лог
		self.log='counted'
		#end of function suite
		#Функция возвращает число таблиц и видов с похожими именами
		return result

	#Определяется базовая функция выборки записей для таблиц и видов
	def select(self,type,names):
		'''Function counts relations'''
		#beginning of function suite
		#print(self.select.__doc__)
		#Выполняется подключение к базе данных
		self.base.connect()
		#Переменной result присваивается результат выборки
		result=self.executer(self.SelectString(type, names))
		#Закрывается подключение к базе данных
		self.base.disconnect()
		#В переменную класса log записывается лог
		self.log='selected'
		#end of function suite
		#Функция возвращает записи для таблиц и видов с заданными именами
		return result

	#Определяется базовая функция выборки записей для похожих таблиц и видов
	def selectlike(self,type,names):
		'''Function selects like relations'''
		#beginning of function suite
		#print(self.selectlike.__doc__)
		#Переменной query присваивается None
		result=[]
		#Выполняется подключение к базе данных
		self.base.connect()
		for name in names:
			#К значению переменной name добавляются %
			name='%'+name+'%'
			#К переменной result прибавляется результат выборки
			result=result+self.executer(self.SelectlikeString(type), name)
		#Закрывается подключение к базе данных
		self.base.disconnect()
		#В переменную класса log записывается лог
		self.log='selected'
		#end of function suite
		#Функция возвращает записи для видов и таблиц с похожими именами
		return result

	#Определяется функция подсчета количества таблиц
	def CountTables(self,names=['']):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц с заданными именами
		return self.count(self.type('t'),names)

	#Определяется функция подсчета количества видов
	def CountViews(self,names=['']):
		'''Function counts views'''
		#beginning of function suite
		#print(self.CountViews.__doc__)
		#end of function suite
		#Функция возвращает число видов с заданными именами
		return self.count(self.type('v'),names)

	#Определяется функция подсчета количества похожих таблиц
	def CountlikeTables(self,names=['']):
		'''Function counts tables'''
		#beginning of function suite
		#print(self.CountlikeTables.__doc__)
		#end of function suite
		#Функция возвращает число таблиц с похожим именами
		return self.countlike(self.type('t'),names)

	#Определяется функция подсчета количества похожих видов
	def CountlikeViews(self,names=['']):
		'''Function counts views'''
		#beginning of function suite
		#print(self.CountlikeViews.__doc__)
		#end of function suite
		#Функция возвращает число видов с похожим именами
		return self.countlike(self.type('v'),names)

	#Определяется функция выборки таблиц
	def SelectTables(self,names=['']):
		'''Function selects tables'''
		#beginning of function suite
		#print(self.SelectTables.__doc__)
		#end of function suite
		#Функция возвращает выборку таблиц с заданными именами
		return self.select(self.type('t'),names)

	#Определяется функция выборки видов
	def SelectViews(self,names=['']):
		'''Function selects views'''
		#beginning of function suite
		#print(self.SelectViews.__doc__)
		#end of function suite
		#Функция возвращает выборку видов с заданными именами
		return self.select(self.type('v'),names)

	#Определяется функция выборки похожих таблиц
	def SelectlikeTables(self,names=['']):
		'''Function selects like tables'''
		#beginning of function suite
		#print(self.SelectlikeTables.__doc__)
		#end of function suite
		#Функция возвращает выборку таблиц с похожими именами
		return self.selectlike(self.type('t'),names)

	#Определяется функция выборки похожих видов
	def SelectlikeViews(self,names=['']):
		'''Function selects like views'''
		#beginning of function suite
		#print(self.SelectlikeViews.__doc__)
		#end of function suite
		#Функция возвращает выборку видов с похожими именами
		return self.selectlike(self.type('v'),names)

	#end of class relations suite

class view:
	"This class is a base class to manipulate a view"
	#beginning of class suite
	#print (self.__doc__)
	#Инициализация методов класса
	def __init__(self):
		self.base=base()
		self.relations=relations()
		self.log=None
		self.param=''

	def SqlName(self, name):
		"Function returns sql string for the view name"
		return 'X_OASUP_SO_'+name

	def SqlFields(self, fields):
		"Function returns sql string for the view fields"
		return ' '+'('+', '.join(fields)+')'

	def SqlCreate(self, name, fields, query, param):
		"Function returns sql string for the view create query"
		return "CREATE "+param+" VIEW "+self.SqlName(name)+self.SqlFields(fields)+" AS "+query

	def SqlDrop(self, name):
		"Function returns sql string for the view drop query"
		return "DROP VIEW "+self.SqlName(name)

	def count(self, name):
		'''Function counts views with the name of the view'''
		#beginning of function suite
		#print(self.count.__doc__)
		#end of function suite
		#Функция возвращает результат выполнения функции self.FdbArticlesToImport.CountViews() с именем вида в качестве аргумента
		return self.relations.CountViews([self.SqlName(name)])
			
	def create(self, name, fields, query, param):
		'''Function creates the view '''
		#beginning of function suite
		#print(FdbArticlesToImport.create.__doc__)
		#Подсчетывается количество видов с данным именем
		before=self.count(name)
		#Если количество=0
		if before==0:
			#Выполняется подключение к базе данных
			self.base.connect()
			# Выполняется запрос на создание вида в Firebird:
			self.base.cursor.execute(self.SqlCreate(name, fields, query, param))
			#commit
			self.base.conn.commit()
			#Закрывается подключение к базе данных
			self.base.disconnect()
			#Подсчетывается количество видов с данным именем
			result=self.count(name)-before
			#В переменную класса log записывается лог
			self.log='created'
		else:
			#Переменной result присваивается нулевое значение
			result=0
			#В переменную класса log записывается лог
			self.log='exists'
		#end of function suite
		#Функция возвращает количество созданных видов
		return result

	def drop(self, name):
		'''Function drops the view'''
		#beginning of function suite
		#print(FdbArticlesToImport.drop.__doc__)
		#Подсчетывается количество видов с данным именем
		before=self.count(name)
		#Если количество не равно нулю:
		if before!=0:
			#Выполняется подключение к базе данных
			self.base.connect()
			# Выполняется запрос на удаление вида в Firebird:
			self.base.cursor.execute(self.SqlDrop(name))
			#commit
			self.base.conn.commit()
			#Закрывается подключение к базе данных
			self.base.disconnect()
			#Подсчетывается количество видов с данным именем
			result=before-self.count(name)
			self.log='droped'
		else:
			#Переменной result присваивается нулевое значение
			result=0
			#В переменную класса log записывается лог
			self.log='does not exist'
		#end of function suite
		#Функция возвращает количество уничтоженных видов
		return result

	#end of class view suite

class aview:
	"This class is a manipulator for articles to import view in firebird"
	#beginning of class suite
	#print (self.__doc__)
	def __init__(self):
		self.view=view()
		self.name=''
		self.fields=[]
		self.query=''
		self.param=''

	#Определяется функция подсчета количества видов с данным именем
	def count(self):
		return self.view.count(self.name)
		
	#Определяется функция создания вида
	def create(self):
		return self.view.create(self.name, self.fields, self.query, self.param)
		
	#Определяется функция уничтожения вида
	def drop(self):
		return self.view.drop(self.name)

	#Заменяется родительская функция
	def SqlName(self):
		"Function returns sql string for the view name"
		return self.view.SqlName(self.name)
	
	#Заменяется родительская функция
	def SqlFields(self):
		"Function returns sql string for the view fields"
		return self.view.SqlFields(self.name)
		
	#Заменяется родительская функция
	def SqlCreate(self):
			"Function returns sql string for the view create query"
			return self.view.SqlCreate(self.name, self.fields, self.query, self.param)
	
	#Заменяется родительская функция
	def SqlDrop(self, name):
			"Function returns sql string for the view drop query"
			return self.view.SqlDrop(self.name)

	#end of class aview suite


#Вывод ошибок возвращается "в исходное положение"

#sys.stderr.close()
#sys.stderr = sys.__stderr__